#define _GNU_SOURCE

#include "app_serial.h"
#include "log/log.h"

int app_serial_setBaudRate(Device *device, BaudRate baudRate)
{
    // 读取串口属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性
    cfsetspeed(&attr, baudRate);

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("Failed to set baud rate");
        return -1;
    }
    log_debug("Set baud successfully");

    return 0;
}

int app_serial_setParity(Device *device, Parity parity){
    // 读取串口属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性
    attr.c_cflag &= ~(PARENB | PARODD); // 清除校验位
    attr.c_cflag |= parity; // 指定校验位

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("Failed to set parity");
        return -1;
    }
    log_debug("Set parity successfully");

    return 0;
}

int app_serial_setStopBit(Device *device, StopBit stopBit){
    // 读取串口属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性
    attr.c_cflag &= ~CSTOPB; // 清除停止位
    attr.c_cflag |= stopBit; // 指定停止位

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("Failed to set stop bit");
        return -1;
    }
    log_debug("Set stop bit successfully");

    return 0;
}

int app_serial_setBlock(Device *device, int is_block){
    // 读取串口属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性
    if (is_block)
    {
        attr.c_cc[VMIN] = 1;    // 至少读取一个字符才返回
        attr.c_cc[VTIME] = 0;   // 没有读到数据就会一直等待
    }else{
        attr.c_cc[VMIN] = 0;    // 最少读取字符数为0
        attr.c_cc[VTIME] = 2;   // 单位为100ms，等待时间为0.2秒
    }

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("Failed to set block mode");
        return -1;
    }
    log_debug("Set block mode successfully");

    return 0;
}

int app_serial_setRaw(Device *device){
    // 读取串口属性
    struct termios attr;
    tcgetattr(device->fd, &attr);

    // 修改属性
    cfmakeraw(&attr);   // 设置原始模式

    // 设置串口属性
    int result = tcsetattr(device->fd, TCSAFLUSH, &attr);
    if (result != 0)
    {
        log_error("Failed to set raw mode");
        return -1;
    }
    log_debug("Set raw mode successfully");

    return 0;
}

int app_serial_init(Device *device){
    app_serial_setBaudRate(device, BR_9600);
    app_serial_setParity(device, Parity_NONE);
    app_serial_setStopBit(device, SB_1);
    app_serial_setBlock(device, 0); // 此处修改不生效
    app_serial_setRaw(device);

    // 刷新
    int result = app_serial_flush(device);
    if (result != 0)
    {
        log_error("Failed to flush serial port");
        return -1;
    }
    log_debug("Flush serial port successfully");

    return 0;
}

/**
 * @brief 刷新
 * 
 * @param device 设备结构体
 * @return int 0: 成功, -1: 失败
 */
int app_serial_flush(Device *device){
    return tcflush(device->fd, TCIOFLUSH);
}
